package com.clp.protocol.iec104;

import com.clp.protocol.iec104.definition.Ta;
import com.clp.protocol.iec104.definition.Tc;
import com.clp.protocol.iec104.definition.Tm;
import com.clp.protocol.iec104.server.*;
import com.clp.protocol.iec104.server.async.SlaveFuture;
import com.clp.protocol.iec104.server.async.SlaveFutureListener;
import com.clp.protocol.iec104.server.pipeline.filter.IpWhiteListFilterRule;
import com.clp.protocol.iec104.server.pipeline.state.data.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * IEC104子站功能说明：
 * 1、基于Netty NIO多路复用；异步编程模式；
 * 2、较为完整的启动流程：启动传输响应-》初始化结束-》...
 * 3、支持主站IP过滤，在白名单之外的主站连接将被拒绝；
 * 4、支持遥测短浮点数；单点/双点遥信的总召唤、变化数据上送（需要根据具体的业务数据进行调用）；
 * 5、支持遥控和遥调过程（需要根据具体的场景进行设置）
 * 6、支持总召唤、电度量召唤（根据具体业务场景进行调用）
 */
public class TestServer {
    public static void main(String[] args) throws Throwable {
        Iec104SlaveManager slaveManager = Iec104SlaveManager.get();
        // 说明：基于Netty的主从Reactor模式，Netty线程仅用于处理IO，不处理实际业务逻辑，以提升IO效率
        // 可通过创建自定义执行器来处理业务逻辑，如查询收集设备测值数据等
        ExecutorService executorService = Executors.newFixedThreadPool(4);

        SlaveFuture<Void> slaveFuture = slaveManager.openSlave(
                SlaveConfig.configurer()
                        .local("127.0.0.1", 2404) // 本机IP和端口号设置
                        .rtuAddr(1) // 公共地址
                        .controlConfig(SlaveControlConfig.configurer() // 控制配置
                                .t0t1t2t3(6, 3, 2, 4) // t0, t1, t2 ,t3 超时时间，单位为秒
                                .kw(12, 8) // 要求 k > w
                                .ipFilterRule(new IpWhiteListFilterRule("127.0.0.1", "172.18.83.112")) // 主站IP白名单
                                .configOk()
                        )
                        .dataConfig(SlaveDataConfig.configurer() // 数据配置
                                // 总召唤处理器，这里是模拟实现，可根据具体场景自行实现该DataReactor
                                .totalCall100DataReactor(new TotalCall100DataReactor(executorService, TotalCall100DataReactor.TmDataType.FLOAT,
                                        TotalCall100DataReactor.TsDataType.ONE_POINT) {
                                    @Override
                                    protected boolean accept0(SlaveChannel slaveChannel) {
                                        return true;
                                    }

                                    @Override
                                    protected List<TmData> collectTmData0(SlaveChannel slaveChannel) {
                                        List<TmData> tmDataList = new ArrayList<>(100);
                                        Random random = new Random();
                                        for (int i = 0; i < 100; i++) {
                                            if (random.nextBoolean()) {
                                                int addr = i;
                                                tmDataList.add(new TmData() {
                                                    @Override
                                                    public BigDecimal getValue() {
                                                        return BigDecimal.valueOf(0);
                                                    }

                                                    @Override
                                                    public boolean isValid() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public int getAddress() {
                                                        return addr;
                                                    }
                                                });
                                            }
                                        }
                                        return tmDataList;
                                    }

                                    @Override
                                    protected List<TsData> collectTsData0(SlaveChannel slaveChannel) {
                                        List<TsData> tsDataList = new ArrayList<>(100);
                                        Random random = new Random();
                                        for (int i = 0; i < 100; i++) {
                                            if (random.nextBoolean()) {
                                                int addr = i;
                                                tsDataList.add(new TsData() {
                                                    @Override
                                                    public boolean isSwitchOn() {
                                                        return random.nextBoolean();
                                                    }

                                                    @Override
                                                    public boolean isValid() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public boolean isCurrVal() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public boolean isReplaced() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public boolean isLocked() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public int getAddress() {
                                                        return addr;
                                                    }
                                                });
                                            }
                                        }
                                        return tsDataList;
                                    }
                                })
                                // 电度量召唤处理器，这里是模拟实现，可根据具体场景自行实现该DataReactor
                                .totalCall101DataReactor(new TotalCall101DataReactor(executorService,
                                        TotalCall101DataReactor.TpDataType.CUMULANT) {
                                    @Override
                                    protected boolean accept0(SlaveChannel slaveChannel) {
                                        return true;
                                    }

                                    @Override
                                    protected List<TpData> collectTpData0(SlaveChannel slaveChannel) {
                                        List<TpData> tpDataList = new ArrayList<>(100);
                                        Random random = new Random();
                                        for (int i = 0; i < 100; i++) {
                                            if (random.nextBoolean()) {
                                                int addr = i;
                                                tpDataList.add(new TpData() {
                                                    @Override
                                                    public long getValue() {
                                                        return 0;
                                                    }

                                                    @Override
                                                    public boolean isValid() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public boolean isAdjusted() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public boolean isOverflowed() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public int getSeq() {
                                                        return 0;
                                                    }

                                                    @Override
                                                    public int getAddress() {
                                                        return addr;
                                                    }
                                                });
                                            }
                                        }
                                        return tpDataList;
                                    }
                                })
                                // 遥控命令处理器，这里是模拟实现，可根据具体场景自行实现该DataReactor
                                .tcDataReactor(new TcDataReactor(executorService, Tc.Type.ONE_POINT) {
                                    @Override
                                    public CompletableFuture<Boolean> acceptSelect(SlaveChannel slaveChannel, int infoObjAddr) {
                                        return CompletableFuture.completedFuture(true);
                                    }

                                    @Override
                                    public CompletableFuture<Boolean> acceptExecute(SlaveChannel slaveChannel, int infoObjAddr) {
                                        return CompletableFuture.completedFuture(true);
                                    }
                                })
                                // 遥调命令处理器，这里是模拟实现，可根据具体场景自行实现该DataReactor
                                .taDataReactor(new TaDataReactor(executorService, Ta.Type.FLOAT) {
                                    @Override
                                    public CompletableFuture<Boolean> acceptSelect(SlaveChannel slaveChannel, int infoObjAddr) {
                                        return supplyAsync(() -> true);
                                    }

                                    @Override
                                    public CompletableFuture<Boolean> acceptExecute(SlaveChannel slaveChannel, int infoObjAddr) {
                                        return supplyAsync(() -> true);
                                    }
                                })
                                .tmVaryType(Tm.VaryType.FLOAT) // 遥测变化类型
                                .configOk()
                        )
                        .configOk()
        );

        // 异步处理打开结果
        slaveFuture.addListener(new SlaveFutureListener<Void>() {
            @Override
            public void operationComplete(SlaveFuture<Void> future) {
                if (future.isSuccess()) {
                    System.out.println("端口打开成功");
                } else {
                    System.out.println("端口打开失败,原因：" + future.cause());
                }
            }
        });

        // -------------- 等待其运行一段时间 ---------------------------
//        Thread.sleep(60 * 60 * 1000);

        // 关闭该子站
//        slaveManager.closeSlave(slaveFuture.slave());
//        executorService.shutdown();
    }
}
